# @Time : 2024-10-23 10:02
# @Author : Fioman 
# @Phone : 13149920693
"""
构建字典的各种方式
1) {} 大括号
2) dict()
3) 字典推导式
4) 字典型字符串
"""
import json

# region 1. 使用大括号构建字典
# 构建空字典
dt = {}
print(len(dt), type(dt))
# dt 也不是True,也不是False,如果使用if判断返回False
if not dt:
    print("空字典 在if语句中是False")
print("dt is False: {}".format(dt is False))  # dt 也不是False
print("not dt is True: {}".format(not dt is True))  # yes,所以空列表,空集合只有在if语句表达式或者是not
# 之后才会转换为True或者False,它本身和True或者False对比都返回的是False
# 构建非空字典
dt = {"A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6}
print(len(dt), type(dt))
if dt:
    print("非空字典 在 if 语句中是True")
# endregion

# region 2. dict构建字典
# 1) 构建空字典
dt = dict()
print(len(dt), type(dt))

# 2) dict() 根据关键字形参,键值对构建字典
dt = dict(A=1, B=2, C=3, D=4, E=5, F=6)
print(dt, len(dt))

# 3) dict() 键值对序列, 序列中的元素需要二元元组或者列表
lst = [("key1", "value1"), ("key2", "value2")]  # 元组列表
dt = dict(lst)
print(dt, len(dt))
lst = [["key1", "value1"], ["key2", "value2"]]  # 列表列表
dt = dict(lst)
print(dt, len(dt))
tup = (("key1", "value1"), ("key2", "value2"))  # 元组元组
dt = dict(tup)
print(dt, len(dt))
tup = (["key1", "value1"], ["key2", "value2"])  # 元组列表
print(dt, len(dt))
# 错误
# lst = [("key1", "value1"), ("key2", "value2"), ("key3", "value3", "无效数据")]
# dt = dict(lst) # ValueError

# 4) dict() 配合zip函数构建字典
keys = ["a", "b", "c", "d", "e", "f"]
values = [1, 2, 3, 4, 5, 6]
dt = dict(zip(keys, values))
print(dt, len(dt))

# 5) dict(otherdict) # 通过其他字典构建一个字典(浅拷贝)
newDt = dict(dt)
print(newDt, len(newDt))

# 6) 通过dict.fromkeys(iterable,None) 从可迭代序列构建字典,并指定默认值
dt = dict.fromkeys(range(10), "A")
print(dt, len(dt))
# endregion

# region 3. 字典推导式 {key,key*2 for key in iterble }
dt = {key: value for key in range(5) for value in range(5)}
print(dt, len(dt))  # 这种写法一般是不对的,但是也能生成一个字典,覆盖方式.相当于最后一次循环才生效
# {0: 4, 1: 4, 2: 4, 3: 4, 4: 4} 5
dt = {key: value for key, value in zip(range(5), range(5))}  # 这样才是对的
print(dt, len(dt))  # zip对象到底是个什么东西,就是可以将两个序列合并为1个序列,zip,不仅仅可以将两个序列
# 合并为1个序列,也可以将三个序列合并为1个序列,这样序列中的每个元素都是包含三个元素了.比如
zipObj = zip(range(5), range(5), range(5))
for a, b, c in zipObj:
    print(a, b, c)
# endregion

# region 4. json.loads 从json字符串构建字典
# jsonStr = "{'key1': 'value1', 'key2': 'value2'}" # 这种就是错误的,需要里面是双引号
jsonStr = '{"key1": "value1", "key2": "value2"}'
d = json.loads(jsonStr)
print(d, type(d))
# endregion

# region 5. copy 和 deepcopy创建字典
# copy 和 dict(original) 的方式是一样的,都是浅拷贝,浅拷贝就是只拷贝第一层的内存数据,如果dict保存的是
# 一个可变的类型,那么它只是拷贝这个可变类型的地址,如果副本发生变化,被拷贝的对象也会发生变化.
dt = {"name": "Fioman", "Skills": ["Python", "C#", "React"]}
dtCopy01 = dict(dt)
dtCopy02 = dt.copy()
print(dt, dtCopy01, dtCopy02)

# 现在随便改变一个,比如改变dtCopy01
dtCopy01["Skills"].append("C++")
print(dt, dtCopy01, dtCopy02)  # 三个里面都有C++
# 如果是指改变name
dtCopy01["name"] = "Hammer"
print(dt, dtCopy01, dtCopy02)  # 只有dtCopy01发生了改变,以为这个不是引用类型,它指向的就是保存字符串
# 的地方

dt = {"name": "Fioman", "Skills": ["Python", "C#", "React"]}
# 深拷贝
from copy import deepcopy

dtDeepCopy = deepcopy(dt)
dtDeepCopy["Skills"].append("C++")
print(dt, dtDeepCopy)  # dt并没有C++ ,说明深拷贝和引用对象和之前的被拷贝的引用对象不是同一个对象

# endregion

# region 6. collections.defaultdict 带有默认值的字典,可以指定类型
from collections import defaultdict

d = defaultdict(list)
d["a"].append(123)
print(d)
# 无参lambda ,直接返回10,创建带有默认值的字典.
d = defaultdict(lambda: 10)
print(d["a"])
# endregion

# region 7. OrderDict 保持好插入顺序
# Python 3.6 之后 dict也会保持插入的顺序了
d = dict()
d["a"] = 1
d["b"] = 2
d["c"] = 3
print(d)

d = dict()
d["c"] = 3
d["b"] = 2
d["a"] = 1
print(d)
# 所以不需要OrderDict了
from collections import OrderedDict

d = OrderedDict([("a", 1), ("b", 2), ("c", 3)])
print(d)
# endregion

# region 8. update() 方法创建或者更新字典
d1 = {"key1": "value1", "key2": "value2"}
d2 = {"key3": "value3", "key4": "value4"}
d1.update(d2)  # 更新合并字典,将两个字典进行合并
print(d1)
d3 = {"key1": "A", "key2": "B"}
d1.update(d3)  # 当要合并的字典的键已经存在的时候就是更新字典
print(d1)
# endregion

# region 9. setdefault() 给字典创建默认值
# setdefault() 方法可以插入键值对,如果键不存在则添加,并返回对要给你值,如果键已经存在了,则返回对应值
# 相当于是比get()多了一个功能,就是发现get的时候键不存在就创建一个默认值进去,再get
d = {}
defalutValue = d.setdefault("A", "value3")
print(defalutValue, d)
# endregion
